package com.boxtelecom.services;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import com.boxtelecom.interfaces.IFacebookService;
import com.boxtelecom.interfaces.IFacebookServiceListener;
import com.boxtelecom.users.FacebookUser;
import com.facebook.android.AsyncFacebookRunner;
import com.facebook.android.Facebook;
import com.facebook.android.FacebookError;

import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
import android.widget.Toast;

public class FacebookService extends Service implements IFacebookService{

	private static AsyncFacebookRunner _myAsyncFacebookRunner = null;
	private List<IFacebookServiceListener> _listeners = null;
	
	@Override
	public IBinder onBind(Intent arg0) {
		// TODO Auto-generated method stub
		return new LocalBinder<FacebookService>(this);
		//return _myBinder;
	}
	
	@Override
	public boolean onUnbind(Intent intent) {
		// TODO Auto-generated method stub
		
		
		return super.onUnbind(intent);
	}

	/**
	 * create a Asynchronous variable to interact with the Graph API
	 * @param aFacebook the facebook instance that we are connected to
	 */
	public void createAsyncFacebookRunner(Facebook aFacebook){
		_myAsyncFacebookRunner = new AsyncFacebookRunner(aFacebook);
	}
	
	/**
	 * logout from facebook
	 */
	public void logout(){
		_myAsyncFacebookRunner.logout(getApplicationContext(), new logoutListener());
	}
	
	/**
	 * call the asynchronous task that interact with the Graph API
	 * to the get the information regarding the connected user
	 */
	public void getUserInfo(){
		_myAsyncFacebookRunner.request("me", new userListener());
	}
	
	/**
	 * call the asynchronous task to download the picture of the user
	 * used in the case to get the picture of the connected user
	 * @param id the picture to download
	 */
	public void getUserPicture(String id){
		new downloadUserPictureAsyncTask().execute(id);
	}

	/**
	 * call the asynchronous task that interact with the Graph API
	 * to the get the friends list of the connected user
	 */
	public void getFriendsList(){
		_myAsyncFacebookRunner.request("me/friends", new friendListListener());
	}

	/**
	 * call the asynchronous task that interact with the Graph API
	 * to the get the information of friend of the connected user
	 */
	public void getFriendsInfo(String id){
		_myAsyncFacebookRunner.request(id, new friendListener());
	}
	
	/**
	 * call the asynchronous task that interact with the Graph API
	 * to the get the friends list of the connected user
	 * used if there is new friends
	 */
	public void getMissingFriendsInfo(String id){
		_myAsyncFacebookRunner.request(id, new missingFriendListener());
	}
	
	/**
	 * call the asynchronous task that interact with the Graph API
	 * to the get the friends list of the connected user
	 * used to check for updates
	 */
	public void updateFriendsInfo(String id){
		_myAsyncFacebookRunner.request(id, new updateListener());

	}

	/**
	 * call the asynchronous task to download the picture of the user
	 * used in the case of a friend
	 * @param id the picture to download
	 */
	public void getFriendPicture(String id){
		new downloadFriendPictureAsyncTask().execute(id);
	}
	
	/**
	 * call the asynchronous task to download the picture of the user
	 * used if there is new friends
	 * @param id the picture to download
	 */
	public void getMissingFriendPicture(String id){
		new downloadMissingFriendPictureAsyncTask().execute(id);
	}
	
	/**
	 * call the asynchronous task that interact with the Graph API
	 * to post a stream to the wall of a friend
	 * @param id the id of the user we want to post the message
	 * @param params the message to post
	 */
	public void postWall(String id, Bundle params){
		_myAsyncFacebookRunner.request(id + "/feed", params, "POST", new postWallListener(), null);
	}
	
	/* ******************** */
	/*                      */
	/*       LISTENERS      */
	/*                      */
	/* ******************** */
	
	/**
	 * Callback class when logout from facebook 
	 */
	private class logoutListener implements
	com.facebook.android.AsyncFacebookRunner.RequestListener {
	
		@Override
		public boolean onComplete(String response, Object state) {
			// TODO Auto-generated method stub
			fireError("Logged out");

			return false;
		}
		
		@Override
		public boolean onIOException(IOException e, Object state) {
			// TODO Auto-generated method stub
			fireError(e.getMessage());
			Log.d("user", e.getMessage());
			return false;
		}
		
		@Override
		public boolean onFileNotFoundException(FileNotFoundException e,
				Object state) {
			// TODO Auto-generated method stub
			fireError(e.getMessage());
			Log.d("user", e.getMessage());
			return false;
		}
		
		@Override
		public boolean onMalformedURLException(MalformedURLException e,
				Object state) {
			// TODO Auto-generated method stub
			fireError(e.getMessage());
			Log.d("user", e.getMessage());
			return false;
		}
		
		@Override
		public boolean onFacebookError(FacebookError e, Object state) {
			// TODO Auto-generated method stub
			fireError(e.getMessage());
			Log.d("user", e.getMessage());
			return false;
		}
	}
	
	/**
	 * Callback class when the user information had been received
	 * notify the user's information to the listeners if there was any errors
	 * else notify the error
	 * @author Boxadmin
	 *
	 */
	private class userListener implements com.facebook.android.AsyncFacebookRunner.RequestListener {

		@Override
		public boolean onComplete(String response, Object state) {
			// TODO Auto-generated method stub
			Log.d("user", response);

			try {
				final JSONObject json = new JSONObject(response);
				
				FacebookUser user = new FacebookUser();
								
				String id = json.getString("id");
				user.setId(id);
				
				String name = json.getString("name");
				user.setName(name);
				
				if(json.has("first_name")){
					String fn = json.getString("first_name");
					user.setFirstName(fn);
				}
				
				if(json.has("last_name")){
					String ln = json.getString("last_name");
					user.setLastName(ln);
				}
												
				if(json.has("birthday")){
					String birthday = json.getString("birthday");
					user.setBirthday(birthday);		
					user.setSigneAstroFromBirthday(user.getBirth());
				} else {
					user.setBirthday("null");
					user.setSigneAstro("null");
					user.setIdSigneAstro(0);
				}
				
				if(json.has("mobile_phone")){
					Log.d("debug", json.getString("mobile_phone"));
				} else {
					Log.d("debug", "no phone number");
				}
				
				if(json.has("updated_time")){
					String update = json.getString("updated_time");
					user.setUpdatedTime(update);
				}
				
				user.setPicturePath("null");
				
				fireUserInfo(user);
				
			} catch (JSONException e) {
				// TODO Auto-generated catch block
				fireError(e.getMessage());
				e.printStackTrace();
			}
			return true;
		}

		@Override
		public boolean onIOException(IOException e, Object state) {
			// TODO Auto-generated method stub
			fireError(e.getMessage());
			Log.d("user", e.getMessage());
			return false;
		}

		@Override
		public boolean onFileNotFoundException(FileNotFoundException e,
				Object state) {
			// TODO Auto-generated method stub
			fireError(e.getMessage());
			Log.d("user", e.getMessage());
			return false;
		}

		@Override
		public boolean onMalformedURLException(MalformedURLException e,
				Object state) {
			// TODO Auto-generated method stub
			fireError(e.getMessage());
			Log.d("user", e.getMessage());
			return false;
		}

		@Override
		public boolean onFacebookError(FacebookError e, Object state) {
			// TODO Auto-generated method stub
			fireError(e.getMessage());
			Log.d("user", e.getMessage());
			return false;
		}	
	}

	/**
	 * Callback class when the list of friends had been received
	 * notify the user's friend list to the listeners if there was any errors
	 * else notify the error
	 * @author Boxadmin
	 *
	 */
	private class friendListListener implements com.facebook.android.AsyncFacebookRunner.RequestListener{

		@Override
		public boolean onComplete(String response, Object state) {
			// TODO Auto-generated method stub
			Log.d("FriendListListener",
					"response.length(): " + response.length());
			Log.d("FriendListListener", "Response: " + response);
			
			ArrayList<String> friends = new ArrayList<String>();

			try {
				final JSONObject json = new JSONObject(response);
				JSONArray d = json.getJSONArray("data");
				int l = (d != null ? d.length() : 0);
				Log.d("FriendListListener", "d.length(): " + l);

				for (int i = 0; i < l; i++) {
					JSONObject o = d.getJSONObject(i);
					String id = o.getString("id");
					friends.add(id);
					
					Log.d("DEBUG", o.getString("name"));
				}
							
				fireFriendList(friends);
				
			} catch (JSONException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				fireError(e.getMessage());
			}
			return true;
		}

		@Override
		public boolean onIOException(IOException e, Object state) {
			// TODO Auto-generated method stub
			Log.d("FriendListListener", e.getMessage());
			fireError(e.getMessage());
			return false;
		}

		@Override
		public boolean onFileNotFoundException(FileNotFoundException e,
				Object state) {
			// TODO Auto-generated method stub
			Log.d("FriendListListener", e.getMessage());
			fireError(e.getMessage());
			return false;
		}

		@Override
		public boolean onMalformedURLException(MalformedURLException e,
				Object state) {
			// TODO Auto-generated method stub
			Log.d("FriendListListener", e.getMessage());
			fireError(e.getMessage());
			return false;
		}

		@Override
		public boolean onFacebookError(FacebookError e, Object state) {
			// TODO Auto-generated method stub
			Log.d("FriendListListener", e.getMessage());
			fireError(e.getMessage());
			return false;
		}		
	}

	/**
	 * Callback class when the user information had been received
	 * notify the user's information to the listeners if there was any errors
	 * else notify the error
	 * used in the case of getting the information of a friend
	 * @author Boxadmin
	 *
	 */
	private class friendListener implements com.facebook.android.AsyncFacebookRunner.RequestListener{

		@Override
		public boolean onComplete(String response, Object state) {
			// TODO Auto-generated method stub
			
			//Log.d("friendListener", response);

			try {
				
				final JSONObject json = new JSONObject(response);
								
				FacebookUser friend = new FacebookUser();
				
				String id = json.getString("id");
				
				friend.setId(id);
				
				if(json.has("name")){
					String name = json.getString("name");
					friend.setName(name);
				}
				
				if(json.has("first_name")){
					String fn = json.getString("first_name");
					friend.setFirstName(fn);
				}

				if(json.has("last_name")){
					String ln = json.getString("last_name");
					friend.setLastName(ln);
				}

				if(json.has("birthday")){
					String birthday = json.getString("birthday");
					friend.setBirthday(birthday);
					friend.setSigneAstroFromBirthday(birthday);
				} else {
					friend.setBirthday("null");
					friend.setSigneAstro("null");
				}
				
				if(json.has("updated_time")){
					String time = json.getString("updated_time");
					friend.setUpdatedTime(time);
				}
				
				fireFriendInfo(friend);

				Log.d("Friend Listener", id + " | "+ friend.getFirstName() + " | " + friend.getLastName() + " | " + friend.getBirth() + " | " + friend.getSigneAstro());
			
			} catch (JSONException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				fireError(e.getMessage());
			}
			return true;
			
		}

		@Override
		public boolean onIOException(IOException e, Object state) {
			// TODO Auto-generated method stub
			Log.d("friendistener", e.getMessage());
			fireError(e.getMessage());
			return false;
		}

		@Override
		public boolean onFileNotFoundException(FileNotFoundException e,
				Object state) {
			// TODO Auto-generated method stub
			Log.d("friendistener", e.getMessage());
			fireError(e.getMessage());
			return false;
		}

		@Override
		public boolean onMalformedURLException(MalformedURLException e,
				Object state) {
			// TODO Auto-generated method stub
			Log.d("friendistener", e.getMessage());
			fireError(e.getMessage());
			return false;
		}

		@Override
		public boolean onFacebookError(FacebookError e, Object state) {
			// TODO Auto-generated method stub
			Log.d("friendistener", e.getMessage());
			fireError(e.getMessage());
			return false;
		}		
	}

	/**
	 * Callback class when the user information had been received
	 * notify the user's information to the listeners if there was any errors
	 * else notify the error
	 * used in the case of getting the information of a friend that he's missing in the database
	 * @author Boxadmin
	 *
	 */
	private class missingFriendListener implements com.facebook.android.AsyncFacebookRunner.RequestListener{

		@Override
		public boolean onComplete(String response, Object state) {
			// TODO Auto-generated method stub
			try {
				
				final JSONObject json = new JSONObject(response);
								
				FacebookUser friend = new FacebookUser();
				
				String id = json.getString("id");
				
				friend.setId(id);
				
				if(json.has("name")){
					String name = json.getString("name");
					friend.setName(name);
				}
				
				if(json.has("first_name")){
					String fn = json.getString("first_name");
					friend.setFirstName(fn);
				}

				if(json.has("last_name")){
					String ln = json.getString("last_name");
					friend.setLastName(ln);
				}

				if(json.has("birthday")){
					String birthday = json.getString("birthday");
					friend.setBirthday(birthday);
					friend.setSigneAstroFromBirthday(birthday);
				} else {
					friend.setBirthday("null");
					friend.setSigneAstro("null");
				}
				
				if(json.has("updated_time")){
					String time = json.getString("updated_time");
					friend.setUpdatedTime(time);
				}
				
				fireMissingFriendInfo(friend);

				Log.d("missingFriendListener", id + " | "+ friend.getFirstName() + " | " + friend.getLastName() + " | " + friend.getBirth() + " | " + friend.getSigneAstro());
			
			} catch (JSONException e) {
				// TODO Auto-generated catch block
				fireError(e.getMessage());
				e.printStackTrace();
			}
			return true;
		}

		@Override
		public boolean onIOException(IOException e, Object state) {
			fireError(e.getMessage());
			return false;
			// TODO Auto-generated method stub
			
		}

		@Override
		public boolean onFileNotFoundException(FileNotFoundException e,
				Object state) {
			fireError(e.getMessage());
					return false;
			// TODO Auto-generated method stub
			
		}

		@Override
		public boolean onMalformedURLException(MalformedURLException e,
				Object state) {
			fireError(e.getMessage());
					return false;
			// TODO Auto-generated method stub
			
		}

		@Override
		public boolean onFacebookError(FacebookError e, Object state) {
			fireError(e.getMessage());
			return false;
			// TODO Auto-generated method stub
			
		}		
	}
	
	/**
	 * Callback class when the user information had been received
	 * notify the user's information to the listeners if there was any errors
	 * else notify the error
	 * used in the case to check if profil has been updated
	 * @author Boxadmin
	 *
	 */
	private class updateListener implements com.facebook.android.AsyncFacebookRunner.RequestListener{

		@Override
		public boolean onComplete(String response, Object state) {
			// TODO Auto-generated method stub
			try {
				
				final JSONObject json = new JSONObject(response);
								
				FacebookUser friend = new FacebookUser();
				
				String id = json.getString("id");
				
				friend.setId(id);
				
				if(json.has("name")){
					String name = json.getString("name");
					friend.setName(name);
				}
				
				if(json.has("first_name")){
					String fn = json.getString("first_name");
					friend.setFirstName(fn);
				}

				if(json.has("last_name")){
					String ln = json.getString("last_name");
					friend.setLastName(ln);
				}

				if(json.has("birthday")){
					String birthday = json.getString("birthday");
					friend.setBirthday(birthday);
					friend.setSigneAstroFromBirthday(birthday);
				} else {
					friend.setBirthday("null");
					friend.setSigneAstro("null");
				}
				
				if(json.has("updated_time")){
					String time = json.getString("updated_time");
					friend.setUpdatedTime(time);
				}
				
				fireUpdate(friend);

				Log.d("updateListener", id + " | "+ friend.getFirstName() + " | " + friend.getLastName() + " | " + friend.getBirth() + " | " + friend.getSigneAstro() + " | " + friend.getUpdatedTime());
			
			} catch (JSONException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				fireError(e.getMessage());
			}
			return true;
		}

		@Override
		public boolean onIOException(IOException e, Object state) {
			// TODO Auto-generated method stub
			Log.d("updatelistener", e.getMessage());
			fireError(e.getMessage());
			return false;
		}

		@Override
		public boolean onFileNotFoundException(FileNotFoundException e,
				Object state) {
			// TODO Auto-generated method stub
			Log.d("updatelistener", e.getMessage());
			fireError(e.getMessage());
			return false;
		}

		@Override
		public boolean onMalformedURLException(MalformedURLException e,
				Object state) {
			// TODO Auto-generated method stub
			Log.d("updatelistener", e.getMessage());
			fireError(e.getMessage());
			return false;
		}

		@Override
		public boolean onFacebookError(FacebookError e, Object state) {
			// TODO Auto-generated method stub
			Log.d("updatelistener", e.getMessage());
			fireError(e.getMessage());
			return false;
		}		
	}
	
	/**
	 * Class that download the picture of an user
	 * used in the case of the connected user
	 * @author Boxadmin
	 *
	 */
	private class downloadUserPictureAsyncTask extends AsyncTask<String, Void, Void> {

		@Override
		protected Void doInBackground(String... params) {
			// TODO Auto-generated method stub
			URL url;
			Bitmap bmp = null;
			String id = params[0];
			String path = "picture" + id;
			
			try {
				url = new URL("http://graph.facebook.com/"+ id + "/picture?type=small");
				
				Log.d("Facebook-Util", "GET URL: " + url.toString());
				
				bmp = BitmapFactory.decodeStream(url.openConnection().getInputStream());
				
				if(bmp != null){
					FileOutputStream fos = openFileOutput(path, Context.MODE_PRIVATE);
					bmp.compress(CompressFormat.JPEG, 90, fos);
					//Log.d("debug", id + " .. " + String.valueOf(bmp.compress(CompressFormat.JPEG, 90, fos)));
					fos.close();
				} else {
					path = "null";
					//Log.d("debug", id + " .. " + picture.getPicturePath());
				}
				
			} catch (MalformedURLException e) {
				// TODO Auto-generated catch block
				Log.d("Error", e.getMessage());
				Toast.makeText(getApplicationContext(), e.getMessage(),
						Toast.LENGTH_LONG).show();
				// e.printStackTrace();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				Log.d("Error", e.getMessage());
				fireError(e.getMessage());
				// e.printStackTrace();
			}
			
			fireUserPicture(path);

			return null;
		}
	}

	/**
	 * Class that download the picture of an user
	 * used in the case of the friends of the connected user
	 * @author Boxadmin
	 *
	 */
	private class downloadFriendPictureAsyncTask extends AsyncTask<String, Void, Void> {

		@Override
		protected Void doInBackground(String... params) {
			// TODO Auto-generated method stub
			URL url;
			Bitmap bmp = null;
			String id = params[0];
			String path = "picture" + id;
			
			FacebookUser picture = new FacebookUser();
			picture.setId(id);
			
			try {
				url = new URL("http://graph.facebook.com/"+ id + "/picture?type=small");

				Log.d("Facebook-Util", "GET URL: " + url.toString());
				
				bmp = BitmapFactory.decodeStream(url.openConnection().getInputStream());

				if(bmp != null){
					FileOutputStream fos = openFileOutput(path, Context.MODE_PRIVATE);
					bmp.compress(CompressFormat.JPEG, 90, fos);
					//Log.d("debug", id + " .. " + String.valueOf(bmp.compress(CompressFormat.JPEG, 90, fos)));
					fos.close();
					
					picture.setPicturePath(path);
				} else {
					picture.setPicturePath("null");
					//Log.d("debug", id + " .. " + picture.getPicturePath());
				}
				
			} catch (MalformedURLException e) {
				// TODO Auto-generated catch block
				fireError(e.getMessage());
				e.printStackTrace();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				fireError(e.getMessage());
				e.printStackTrace();
			}
			
			fireFriendPicture(picture);
/*			
			WifiManager wifi = (WifiManager) getSystemService(Context.WIFI_SERVICE);
			Log.d("debug", wifi.getConnectionInfo().toString() + String.valueOf(wifi.isWifiEnabled()));
			*/
			return null;
		}
	}
	
	/**
	 * Class that download the picture of an user
	 * used in the case if there is friends missing in the database
	 * @author Boxadmin
	 *
	 */
	private class downloadMissingFriendPictureAsyncTask extends AsyncTask<String, Void, Void> {

		@Override
		protected Void doInBackground(String... arg0) {
			// TODO Auto-generated method stub
			URL url;
			Bitmap bmp = null;
			String id = arg0[0];
			String path = "picture" + id;
			
			FacebookUser picture = new FacebookUser();
			picture.setId(id);
			
			try {
				url = new URL("http://graph.facebook.com/"+ id + "/picture?type=small");

				bmp = BitmapFactory.decodeStream(url.openConnection().getInputStream());

				if(!(bmp == null)){
					FileOutputStream fos = openFileOutput(path, Context.MODE_PRIVATE);
					bmp.compress(CompressFormat.JPEG, 90, fos);
					//Log.d("debug", id + " .. " + String.valueOf(bmp.compress(CompressFormat.JPEG, 90, fos)));
					fos.close();
					
					picture.setPicturePath(path);
				} else {
					picture.setPicturePath("null");
					//Log.d("debug", id + " .. " + picture.getPicturePath());
				}
				
			} catch (MalformedURLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				fireError(e.getMessage());
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				fireError(e.getMessage());
			}
			
			fireMissingFriendPicture(picture);

			return null;
		}		
	}
	
	/**
	 * Callback class when a message had been posted to a wall
	 * @author Boxadmin
	 *
	 */
	private class postWallListener implements com.facebook.android.AsyncFacebookRunner.RequestListener{

		@Override
		public boolean onComplete(String response, Object state) {
			// TODO Auto-generated method stub
			return false;
		}

		@Override
		public boolean onIOException(IOException e, Object state) {
			// TODO Auto-generated method stub
			Log.d("Error", e.getMessage());
			fireError(e.getMessage());
			return false;
		}

		@Override
		public boolean onFileNotFoundException(FileNotFoundException e,
				Object state) {
			// TODO Auto-generated method stub
			Log.d("Error", e.getMessage());
			fireError(e.getMessage());
			return false;
		}

		@Override
		public boolean onMalformedURLException(MalformedURLException e,
				Object state) {
			// TODO Auto-generated method stub
			Log.d("Error", e.getMessage());
			fireError(e.getMessage());
			return false;
		}

		@Override
		public boolean onFacebookError(FacebookError e, Object state) {
			// TODO Auto-generated method stub
			Log.d("Error", e.getMessage());
			fireError(e.getMessage());
			return false;
		}
		
	}
	
	@Override
	public void addListener(IFacebookServiceListener listener) {
		// TODO Auto-generated method stub
		if(_listeners == null){
			_listeners = new ArrayList<IFacebookServiceListener>();
		}
		if(!_listeners.contains(listener)){
			_listeners.add(listener);
		}
	}

	@Override
	public void removeListener(IFacebookServiceListener listener) {
		// TODO Auto-generated method stub
		if(_listeners  != null){
			_listeners.remove(listener);
		}
	}
	
	/**
	 * notify the listeners that the information of an user had been downloaded
	 * @param user the information of the user
	 */
	private void fireUserInfo(FacebookUser user){
		if(_listeners != null){
			for(IFacebookServiceListener listener: _listeners){
				listener.userInfo(user);
			}
		}
	}

	/**
	 * notify the listeners that the picture of an user had been downloaded
	 * @param picture the path where the picture is stored
	 */
	private void fireUserPicture(String picture){
		if(_listeners != null){
			for(IFacebookServiceListener listener : _listeners){
				listener.userPicture(picture);
			}
		}
	}
	
	/**
	 * notify the listeners that the friend's list of an user had been downloaded
	 * @param list contains the id of the friend
	 */
	private void fireFriendList(ArrayList<String> list){
		if(_listeners != null){
			for(IFacebookServiceListener listener: _listeners){
				listener.userFriends(list);
			}
		}
	}
	
	/**
	 * notify the listeners that the information of an user had been downloaded
	 * used in the case of it is a friend that had been downloaded 
	 * @param friend the information an user
	 */
	private void fireFriendInfo(FacebookUser friend){
		if(_listeners != null){
			for(IFacebookServiceListener listener: _listeners){
				listener.friendInfo(friend);
			}
		}
	}

	/**
	 * notify the listeners that the information of an user had been downloaded
	 * used in the case of it is a missing friend that had been downloaded
	 * @param missingFriend the information an user
	 */
	private void fireMissingFriendInfo(FacebookUser missingFriend){
		if(_listeners != null){
			for(IFacebookServiceListener listener: _listeners){
				listener.missingFriend(missingFriend);
			}
		}
	}
	
	/**
	 * notify the listeners that the information of an user had been downloaded
	 * used in the case of it is an update
	 * @param update the information an user
	 */
	private void fireUpdate(FacebookUser update){
		if(_listeners != null){
			for(IFacebookServiceListener listener: _listeners){
				listener.updateInfo(update);
			}
		}
	}

	/**
	 * notify the listeners that the picture of an user had been downloaded
	 * used in the case of it is a friend
	 * @param picture the path where the picture is stored
	 */
	private void fireFriendPicture(FacebookUser picture){
		if(_listeners != null){
			for(IFacebookServiceListener listener: _listeners){
				listener.friendPicture(picture);
			}
		}
	}

	/**
	 * notify the listeners that the picture of an user had been downloaded
	 * used in the case of it is a missing friend
	 * @param missingPicture the path where the picture is stored
	 */
	private void fireMissingFriendPicture(FacebookUser missingPicture){
		if(_listeners != null){
			for(IFacebookServiceListener listener: _listeners){
				listener.missingPicture(missingPicture);
			}
		}
	}
	
	/**
	 * notify the listeners that an error occurred
	 * @param error the occurred error
	 */
	private void fireError(String error){
		if(_listeners != null){
			for(IFacebookServiceListener listener: _listeners){
				listener.error(error);
			}
		}
	}
	
}
